#include "RAT_Vector3D.h"

namespace RAT_ENGINE
{
	/// <summary>
	///	Overloads the arithmic operator +, in order to add two vectors to each other.
	/// </summary>
	/// <param name="argVector">The vector that is added to this.</param>
	/// <returns>A RAT_Vector3D of this + argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator+ (const RAT_Vector3D& argVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x + argVector.x;
		vectorResult.y = y + argVector.y;
		vectorResult.z = z + argVector.z;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	///	Overloads the arithmic operator -, in order to subtract two vectors from each other.
	/// </summary>
	/// <param name="argVector">The vector that is subtracted from this.</param>
	/// <returns>A RAT_Vector3D of this - argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator- (const RAT_Vector3D& argVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x - argVector.x;
		vectorResult.y = y - argVector.y;
		vectorResult.z = z - argVector.z;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	///	Overloads the arithmic operator *, in order to calculate the cross product of two vectors.
	/// </summary>
	/// <param name="argVector">The vector that this is multiplied with for the cross product.</param>
	/// <returns>A RAT_Vector3D of this x argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator* (const RAT_Vector3D& argVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vector.
		vectorResult.x = y * argVector.z - z * argVector.y;
		vectorResult.y = z * argVector.x - x * argVector.z;
		vectorResult.z = x * argVector.y - y * argVector.x;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the arithmic operator *, to multiply this vector with a 3x3 matrix, treating this as a row vector.
	/// </summary>
	/// <param name="argMatrix">The matrix that is to be multiplied with.</param>
	/// <returns>A RAT_Vector3D that has been multiplied with argMatrix.</returns>
	RAT_Vector3D RAT_Vector3D::operator* (const RAT_Matrix33& argMatrix) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Calculates the components of vectorResult.
		vectorResult.x = x * argMatrix.R11 + y * argMatrix.R21 + z * argMatrix.R31;
		vectorResult.y = x * argMatrix.R12 + y * argMatrix.R22 + z * argMatrix.R32;
		vectorResult.z = x * argMatrix.R13 + y * argMatrix.R23 + z * argMatrix.R33;

		//Returns vectorResult.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the arithmic operator *, in order to calculate a scalar product.
	/// </summary>
	///<param name ="argScale"> The float that the vector is scaled with. </param>
	/// <returns>A RAT_Vector3D that is the result of this * argScale.</returns>
	RAT_Vector3D RAT_Vector3D::operator* (const float& argScale) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x * argScale;
		vectorResult.y = y * argScale;
		vectorResult.z = z * argScale;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the arithmic operator /, in order to calculate a scalar division.
	/// </summary>
	/// <param name ="argScale"> The float that the vector is scaled with. </param>
	/// <returns>A RAT_Vector3D that is the result of this / argScale.</returns>
	RAT_Vector3D RAT_Vector3D::operator/ (const float& argScale) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x / argScale;
		vectorResult.y = y / argScale;
		vectorResult.z = z / argScale;

		//Returns the result.
		return vectorResult;
	}


	/// <summary>
	/// Overloads the compound operator +=, in order to add two vectors to each other.
	/// </summary>
	/// <param name="argVector"> The vector that is added to this. </param>
	/// <returns>A RAT_Vector3D of this + argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator+= (const RAT_Vector3D& argVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x + argVector.x;
		vectorResult.y = y + argVector.y;
		vectorResult.z = z + argVector.z;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the compound operator -=, in order to subtract two vectors from each other.
	/// </summary>
	/// <param name="argVector"> The vector that is subtracted from this. </param>
	/// <returns>A RAT_Vector3D of this - argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator-= (const RAT_Vector3D& argVector)const 
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x - argVector.x;
		vectorResult.y = y - argVector.y;
		vectorResult.z = z - argVector.z;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the compound operator *=, in order to calculate the cross product of two vectors.
	/// </summary>
	/// <param name="argVector"> The vector that this is multiplied with for the cross product. </param>
	/// <returns>A RAT_Vector3D of this x argVector.</returns>
	RAT_Vector3D RAT_Vector3D::operator*= (const RAT_Vector3D& argVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vector.
		vectorResult.x = y * argVector.z - z * argVector.y;
		vectorResult.y = z * argVector.x - x * argVector.z;
		vectorResult.z = x * argVector.y - y * argVector.x;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the compound operator *, to multiply this vector with a 3x3 matrix, treating this as a row vector.
	/// </summary>
	/// <param name="argMatrix">The matrix that is to be multiplied with.</param>
	/// <returns>A RAT_Vector3D that has been multiplied with argMatrix.</returns>
	RAT_Vector3D RAT_Vector3D::operator*= (const RAT_Matrix33& argMatrix) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Calculates the components of vectorResult.
		vectorResult.x = x * argMatrix.R11 + y * argMatrix.R21 + z * argMatrix.R31;
		vectorResult.y = x * argMatrix.R12 + y * argMatrix.R22 + z * argMatrix.R32;
		vectorResult.z = x * argMatrix.R13 + y * argMatrix.R23 + z * argMatrix.R33;

		//Returns vectorResult.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the compound operator /=, in order to calculate a scalar division.
	/// </summary>
	/// <param name="argScale"> The float that the vector is scaled with.</param>
	/// <returns>A RAT_Vector3D that is the result of this * argScale.</returns>
	RAT_Vector3D RAT_Vector3D::operator*= (const float& argScale) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x * argScale;
		vectorResult.y = y * argScale;
		vectorResult.z = z * argScale;

		//Returns the result.
		return vectorResult;
	}

	/// <summary>
	/// Overloads the compound operator /=, in order to calculate a scalar division.
	/// </summary>
	/// <param name="argScale"> The float that the vector is scaled with. </param>
	/// <returns>A RAT_Vector3D that is the result of this / argScale.</returns>
	RAT_Vector3D RAT_Vector3D::operator/= (const float& argScale) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Adds the attributes of the vectors.
		vectorResult.x = x / argScale;
		vectorResult.y = y / argScale;
		vectorResult.z = z / argScale;

		//Returns the result.
		return vectorResult;
	}


	/// <summary>
	/// Overloads the relational operator ==, in order to compare two vectors.	
	/// </summary>
	/// <param name="argVector">The vector that is to be compared with.</param>
	/// <returns>A boolean that determines if this and argVector are equal.</returns>
	bool RAT_Vector3D::operator== (const RAT_Vector3D& argVector) const
	{
		return x == argVector.x &&
			   y == argVector.y &&
			   z == argVector.z;
	}

	/// <summary>
	///	Overloads the relational operator !=, in order to compare two vectors.
	/// </summary>
	/// <param name="argVector">The vector that is to be compared with.</param>
	/// <returns>A boolean that determines if this and argVector are not equal.</returns>
	bool RAT_Vector3D::operator!= (const RAT_Vector3D& argVector) const
	{
		return x != argVector.x &&
			   y != argVector.y &&
			   z != argVector.z;
	}

	/// <summary>
	/// Calculates the dot product of this and the argVector.
	/// </summary>
	/// <param name="argVector">The vector that is used to calculate a dot product.</param>
	/// <returns>A dot product.</returns>
	float RAT_Vector3D::DotProduct(const RAT_Vector3D& argVector) const
	{
		//Initializes the dot product.
		float dotProduct;

		dotProduct = x * argVector.x +
					 y * argVector.y + 
					 z * argVector.z;

		//Returns the dot product.
		return dotProduct;
	}
	
	/// <summary>
	/// The Hadamard Product is product of a scaling vector and this vector.
	/// </summary>
	/// <param name="argScaleVector">The vector that scales this.</param>
	/// <returns>A scaled vector.</returns>
	RAT_Vector3D RAT_Vector3D::HadamardProduct(const RAT_Vector3D& argScaleVector) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;

		//Calculates the vector.
		vectorResult.x = x * argScaleVector.x;
		vectorResult.y = y * argScaleVector.y;
		vectorResult.z = z * argScaleVector.z;

		//Returns vectorResult.
		return vectorResult;
	}
	
	/// <summary>
	/// Calculates the squared magnitude of this vector.
	/// </summary>
	/// <returns>A float that represents the squared magnitude.</returns>
	float RAT_Vector3D::SquaredMagnitude() const
	{
		//Initialize the float that is to be returned.
		float squaredMagnitude;

		//Calculates the magnitude.
		squaredMagnitude = x*x+y*y+z*z;

		//Returns the squared magnitude.
		return squaredMagnitude;
	}
	
	/// <summary>
	/// Calculates the magnitude of the vector.
	/// </summary>
	/// <param name="argVector"></param>
	/// <returns></returns>
	float RAT_Vector3D::Magnitude() const
	{
		//Initialize the float that is to be returned.
		float magnitude;

		//Calculates the magnitude.
		magnitude = sqrt(x*x+y*y+z*z);

		return magnitude;
	}
	
	/// <summary>
	/// Calculates the Linear Interpolation of two vectors.
	/// </summary>
	/// <param name="argVector">Forms a line with this vector.</param>
	/// <param name="argPoint">Defines the point in percentages on the line. (MUST BE BETWEEN 0 AND 1)</param>
	/// <returns>The interlying vector.</returns>
	RAT_Vector3D RAT_Vector3D::LERP(const RAT_Vector3D& argVector, const float& argPoint) const
	{
		//Initializes the vector that is to be returned.
		RAT_Vector3D vectorResult;
		
		//Calculates the interlying vector.
		vectorResult = *this * (1-argPoint) + argVector * argPoint;

		//Returns vectorResult.
		return vectorResult;
	}

	/// <summary>
	///	Prints the vector in the IO stream.
	/// </summary>
	void RAT_Vector3D::PrintIO() const
	{
		std::cout << "(" <<  x << ", " << y << ", " << z << ")" << std::endl;
	}
}